//全局函数区域
#include<stdio.h>
#define MAX 1024
#include<string.h>
#include<math.h>
/*
	看不懂的话就看看这个
	https://blog.csdn.net/qq_43428547/article/details/88956911
   1.前言：其实没有真正意义的二维数组，人为形象规定叫二维数组比较准确，它的本质就是数组指针，
	  因为二维数组在内存中以线性方式存放；我画个图你可能就明白了
	  int a[3][4];

	  我们初学二维数组的时候是这么表示的
	  a[3][4]


	  a[0][0]		a[0][1]		a[0][2]		a[0][3]
	  a[1][0]		a[1][1]		a[1][2]		a[1][3]
	  a[2][0]		a[2][1]		a[2][2]		a[2][3]	

	  事实上内存是这么存放的：
	  a[0]											    a[1]											a[2]
	   |												|												|																
	   V												V												V
	  a[0][0]		a[0][1]		a[0][2]		a[0][3]		a[1][0]		a[1][1]		a[1][2]		a[1][3]		a[2][0]		a[2][1]		a[2][2]		a[2][3]


	   有点熟悉吧
	   哎嘿，它的本质就是指针数组；因为不管是数组还是指针，它们的本质都是地址。

	2.二维数组的行地址和各个元素地址的表示,数组名与指针的关系
		int a[3][4]
		a;//表示数组'首行'地址，一般用a[0][0]的地址表示
		&a;//将数组看成一个整体,&表示取地址符。这里表示取出整个数组的地址
		a[i];//表示第i行起止元素的地址。
		&a[i];代表第i行的地址,一般用a[i][0]的地址表示；
		a[i] + j ; //表示第i行第j个元素的地址，即&a[i][j]，a[i]就是j == 0 的情况
		a[i][j];//表示第i行第j个元素
		&a[i][j];//代表了第i行第j个元素的地址

		*a;//代表数组a首元素的地址也就是a[0]或者a[0][0]的地址表示
		*(a + i);代表了第i行首元素的地址，*a是i = 0的情况
		*(a + i) + j；//代表了第i行j个元素的地址
		**a；//代表a的首元素的地址也就是a[0][0]
		*(*(a + i) + j);//代表了第i行第j个元素
		
		不理解的话就去看看上节课的科普内容<指针法和下标法>
		这里有个公式可以记一下：*(a+i) == a[i]; 加上个*号会等于指针变量去掉*号右边加个中括号，中括号内的值为指针变量所要增加的值，*(a+i)+j = a[i]+j;
		对于 *(*(a+i)+j) = a[i][j],我们可以先去掉最外面的*变成(*(a+i))[j],再去掉*为a[i][j]


*/

//程序1
//理解 * （解引用）的使用方法<即上节课我们提到的指针法访问数组>

void test1()
{
	char array[2][3][5] = {
		{
			{'A','B','C','D','E'},
			{'F','G','H','I','J'},
			{'K','L','N','M','O'}
		},
		{
			{'P','Q','O','S','T'},
			{'U','V','W','Y','Z'},
			{'a','b','c','d','e'}
		}
	};

	printf("*(*(*array + 1) + 2):%c\n", *(*(*array + 1) + 2));//这个这么解释可能会好一点，*（*(*(array + 0) + 1)+2）即array[0][1][2],下面的就以此类推，
	printf("*(*(*(array + 1) + 1) + 2) : %c\n", *(*(*(array + 1) + 1) + 2));
	printf("***array：%c\n", ***array);
	printf("*(**array + 1):%c", *(**array + 1));
}

//程序2
//利用int (*)[]类型强制转换成二维数组
void test2()
{
	int array[9] = { 1,2,3,4,5,6,7,8,9 };
	int (*p)[3] = (int(*)[3]) & array;//int (*)[3]这个类型你要是上节课能听得懂的话，那就很容易理解，(int (*)[3]&array == *array[3]),取出array整个数组的地址，利用数组指针强制转换成二维数组

	printf("%d\n", p[2][2]);

}

//程序3
//利用程序2将用户输入的前面九个数据以正方形矩阵的方式输出

void test3()
{
	char str[1024];
	printf("请输入一串字符串：");
	for (int i = 0; i < 9; i++)
	{
		scanf("%c", str[i]);
	}

	
	char (*p)[3] = (char (*)[3]) &str;
	
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			printf("%c", p[i][j]);
		}
		printf("\n");
	}


}

//程序4
//利用二维数组实现矩阵打印

void test4()
{
	char str[3][3];//每日小错误，在定义char[MAX][MAX]二维数组的时候，得考虑出现栈溢出情况喔，调试代码显示：0xC00000FD:Stack overflow就是显示栈溢出了
	printf("请输入一串字符串:");
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			str[i][j] = getchar();
		}
	}

	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			printf("%c", str[i][j]);
		}
		printf("\n");
	}

}

//程序5
//求最大的正方形的数组矩阵输出
void test5()

{	
	int length;
	int i, j;
	char arr[MAX];
	printf("请输入一串字符串：");
	fgets(arr,MAX,stdin);

	length = strlen(arr);//利用strlen函数求出计算arr数组的长度，char字符类型占内存一个字节;
	int aver;
	aver = sqrt(length);//sqrt函数是求平方根，这个数学语言对于你来说的话，

	for(i = 0; i < aver; i++)
	{
		for (j = 0; j < aver; j++)
		{
			printf("%c ", arr[i * aver + j]);//你把二维数组变成线性排列方式,那就很好理解了。
		}
		printf("\n");
	}


	
}

//程序6
//利用二维数组进行最大正方形矩阵输出
/*	
	我知道你想试试这个方法，不过它其实是不可行的，因为你不知道最大平方的值，也就不能定义二维数组的宽度，不然就会永远保存到同一行中，上面就是使用一维数组转换为二维数组
*/


//程序7
//利用指针模拟实现最大正方形的矩阵输出

void test7()
{
	char str[1024];
	printf("请输入一段字符串：");
	fgets(str, 1024, stdin);

	int length, aver;
	length = strlen(str);
	aver = sqrt(length);

	/*char (*p)[aver] = char(*)[aver] & str;*/
	//哎哟，这个方法也不行呢因为报错了，要实现这个功能的话就得使用mallco函数，这个函数不是我们现在所能学习的,等到之后学到了再看看吧
}

//程序8
//写一个程序，用户输入待查询年月份（输入格式：2015-03），输出该月份的 PM2.5 值。要求时间范围：2014年8月份 ~ 2016年8月份
//这个没啥难的，就是简单的二维数组的应用
void test8()
{
		float pm25[3][12] = {
				{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 31.3, 35.5, 58.7, 49.6, 55.5},
				{59.8, 54.9, 33.1, 38.2, 26.6, 20.5, 27.8, 38.5, 41.5, 44.7, 38.1, 41.5},
				{34.9, 36.4, 47.5, 37.9, 30.6, 23.4, 26.6, 34.3, 0.0, 0.0, 0.0, 0.0}
		};
		int year, month;

		printf("请输入待查询年月分(年-月): ");
		scanf("%d-%d", &year, &month);

		if (year < 2014 || year > 2016 || month < 1 || month > 12)
		{
			printf("输入数据错误！\n");
		}
		else
		{
			year -= 2014;
			month -= 1;
			if (pm25[year][month])
			{
				printf("%d年%d月广州的PM2.5值是: %.2f\n", year + 2014, month + 1, pm25[year][month]);
			}
			else
			{
				printf("抱歉，该月份未收录数据！\n");
			}
		}

	
}

//主函数
int main()
{	
	/*
		索引				含义
		test1			指针数组和数组指针的混合使用/理解 * （解引用）的使用方法<即上节课我们提到的指针法访问数组>
		test2			利用int (*)[]类型强制转换成二维数组
		test3			利用程序2将用户输入的前面九个数据以正方形矩阵的方式输出
		test4			利用二维数组实现矩阵打印
		test5			求最大的正方形的数组矩阵输出
		test6-7			错误示范，论为什么用二维数组和指针无法实现求最大的正方形的数据矩阵输出
		test8			写一个程序，用户输入待查询年月份（输入格式：2015-03），输出该月份的 PM2.5 值。要求时间范围：2014年8月份 ~ 2016年8月份
	*/
	test7();
	return 0;
}